﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using System.Diagnostics;

namespace Wentong300Cameral
{
    public partial class Discriminate: UserControl
    {
        public Discriminate(Form _parent)
        {
            this.Parent = (Form)_parent;
            myParent = _parent;
            InitializeComponent();
        }

        Mutex mutexThread = new Mutex();

        //自定义设备事件
        public delegate void DiscriminateStatusHandler(Int16 index, string plateNumber, Int16 dType, byte[] picPlateNumber, byte[] picCar, uint alarmType, short carType, int carColor, uint carDirection);
        public event DiscriminateStatusHandler DisCriminateStatus;

        //更新设备事件 
        public delegate void UpdateDeviceEvent(Int16 index, string strIP, uint nType);
        public UpdateDeviceEvent updateDeviceEvent;

        public delegate void UpdatePlateInfo(string strInfo, byte[] picPlateNumber, int nIndex);
        public UpdatePlateInfo plateNumberInfo;

        //创建错误事件
        public delegate void ErrorHandler(Int16 index, string err);
        public ErrorHandler errorEvent;


        //车牌识别的属性 
        private string picturePath = "";
        private Int16 deviceIndex = 0;
        private string password = "";
        private string userName = "";
        private int port = 8000;
        private string ip = "";
        private string currentPlateNumber = "";
        private bool isConnect = false;
        private bool isVideo = false;
        private string errorInfo = "";
        private bool saveToLocal = false;

        public bool SaveToLocal
        {
            get
            {
                return saveToLocal;
            }
            set
            {
                saveToLocal = value;
            }
        }
        public string  imageStorePath { get; set; }

        private IntPtr pUid = new IntPtr();
        private ipcsdk.ICE_IPCSDK_OnDeviceEvent onDeviceEvent;
        private ipcsdk.ICE_IPCSDK_OnPlate onPlate;

        public void SDK_OnDeviceEvent(IntPtr pvParam,
            [In()] [MarshalAs(UnmanagedType.LPStr)] string pcIP,
            uint u32EventType, uint u32EventData1, uint u32EventData2, uint u32EventData3, uint u32EventData4)
        {            
            if (updateDeviceEvent != null)
            {
                //updateDeviceEvent(deviceIndex, pcIP, u32EventType);
                IAsyncResult syncResult = this.BeginInvoke(updateDeviceEvent, deviceIndex, pcIP, u32EventType);
            }
        }

        private string[] strVehicleDir = new string[]
        {
            "车头方向",
            "车尾方向",
            "车头车尾方向"
        };
        private string[] strVehicleColor = new string[] {
            "未知",
            "黑色",
            "蓝色",
            "灰色",
            "棕色",
            "绿色",
            "夜间深色",
            "紫色",
            "红色",
            "白色",
            "黄色"
        };
        private string[] strAlarmType = new string[]{
            "实时_硬触发+临时车辆",
            "实时_视频触发+临时车辆",
            "实时_软触发+临时车辆",
            "实时_硬触发+白名单",
            "实时_视频触发+白名单",
            "实时_软触发+白名单",
            "实时_硬触发+黑名单",
            "实时_视频触发+黑名单",
            "实时_软触发+黑名单",
            "脱机_硬触发+临时车辆",
            "脱机_视频触发+临时车辆",
            "脱机_软触发+临时车辆",
            "脱机_硬触发+白名单",
            "脱机_视频触发+白名单",
            "脱机_软触发+白名单",
            "脱机_硬触发+黑名单",
            "脱机_视频触发+黑名单",
            "脱机_软触发+黑名单",
            "实时_硬触发+过期白名单",
            "实时_视频触发+过期白名单",
            "实时_软触发+过期白名单",
            "脱机_硬触发+过期白名单",
            "脱机_视频触发+过期白名单",
            "脱机_软触发+过期白名单"
        };
        private string[] strVehicleType = new string[]
        {
            "未知",
            "轿车",
            "面包车",
            "大型客车",
            "中型客车",
            "皮卡",
            "非机动车",
            "SUV",
            "MPV",
            "微型货车",
            "轻型货车",
            "中型货车",
            "重型货车"
        };
        public void SDK_OnPlate(IntPtr pvParam,
            [In()] [MarshalAs(UnmanagedType.LPStr)] string pcIP,
            [In()] [MarshalAs(UnmanagedType.LPStr)] string pcNumber,
            [In()] [MarshalAs(UnmanagedType.LPStr)] string pcColor,
            IntPtr pcPicData, uint u32PicLen, IntPtr pcCloseUpPicData, uint u32CloseUpPicLen,
            short nSpeed, short nVehicleType, short s16FalsePlate, short nReserved2,
            float fPlateConfidence, int u32VehicleColor, uint u32PlateType, uint u32VehicleDir, uint u32AlarmType,
            uint u32SerialNum, uint uCapTime, uint u32ResultHigh, uint u32ResultLow)
        {
            int index = (int)pvParam;
            string strInfo = String.Format("车牌识别({0})#", index) + pcIP + "," + pcNumber + "," + pcColor + ","
                + ((nVehicleType >= 0 && nVehicleType <= 12) ? strVehicleType[nVehicleType] : "") +
                ((u32VehicleColor >= 0 && u32VehicleColor <= 9) ? strVehicleColor[u32VehicleColor + 1] : "") + ","
                + ((u32VehicleDir >= 0 && u32VehicleDir <= 2) ? strVehicleDir[u32VehicleDir] : "") + ","
                + ((u32AlarmType >= 0 && u32AlarmType <= 23) ? strAlarmType[u32AlarmType] : "");
            byte[] datajpg2 = null;
            if (u32PicLen > 0)
            {
                IntPtr ptr2 = (IntPtr)pcPicData;
                datajpg2 = new byte[u32PicLen];
                Marshal.Copy(ptr2, datajpg2, 0, datajpg2.Length);
                if(saveToLocal) storePic(datajpg2, pcIP, pcNumber, false);
            }
            byte[] datajpg = null;
            if (u32CloseUpPicLen > 0)
            {
                IntPtr ptr = (IntPtr)pcCloseUpPicData;
                datajpg = new byte[u32CloseUpPicLen];
                Marshal.Copy(ptr, datajpg, 0, datajpg.Length);
                if (saveToLocal) storePic(datajpg, pcIP, pcNumber, true);
            }
            currentPlateNumber = pcNumber;
            this.BeginInvoke(plateNumberInfo, strInfo, datajpg, index);
            txtPlateNumber.Text = pcNumber;
            if (DisCriminateStatus != null && pcNumber.Trim() != "")
            {                
                DisCriminateStatus(deviceIndex, pcNumber, (Int16)u32AlarmType, datajpg, datajpg2, u32AlarmType, nVehicleType, u32VehicleColor, u32VehicleDir);
            }
            else
            {
                errorInfo = "未加载Discriminate事件！";
                errorEvent?.Invoke(deviceIndex, errorInfo);
            }
        }

        public void PlateNumberInfo(string strInfo, byte[] picPlateNumber, int nIndex)
        {
            //显示抓拍图片
            if (null != picPlateNumber)
            {
                MemoryStream ms = new MemoryStream(picPlateNumber);
                Image image = System.Drawing.Image.FromStream(ms);
                pictureBoxPic.Image = image;
            }
            else
            {
                pictureBoxPic.Image = null;
            }
        }

        /// <summary>
        /// 保存抓拍及车牌号图片
        /// </summary>
        /// <param name="picData"></param>
        /// <param name="strIP"></param>
        /// <param name="strNumber"></param>
        /// <param name="bIsPlate"></param>
        public void storePic(byte[] picData, string strIP, string strNumber, bool bIsPlate)
        {
            DateTime dt = new DateTime();
            dt = DateTime.Now;
            //车牌_Temp_年月日_类型_IP_时间戳
            string timestamp = GlobalVariable.GetTimeStampMilliseconds();
            string strPicName = "";
            string strDir = "";
            //imageStorePath = {0}_TEMP_{3}_{2}_{1}_{4}.jpg "Plate" : "PlateFull"
            string filePath = imageStorePath + dt.ToString("yyyyMMdd") + @"\";
            if (String.IsNullOrEmpty(imageStorePath))
            {
                strDir = Application.StartupPath + @"\photo\capture\";
                if (picturePath != "")
                {
                    strDir = picturePath;
                }
                strDir = strDir + strIP + @"\" + dt.ToString("yyyyMMdd");
                if (!Directory.Exists(strDir))
                {
                    Directory.CreateDirectory(strDir);
                }
                strPicName = strDir + @"\" + dt.ToString("yyyyMMddHHmmss") + "_" + strNumber;
                if (bIsPlate)
                    strPicName += "_plate";

                strPicName += ".jpg";
                if (File.Exists(strPicName))
                {
                    int count = 1;
                    while (count <= 10)
                    {
                        strPicName = strDir + @"\" + dt.ToString("yyyyMMddHHmmss") + "_" + strNumber;
                        if (bIsPlate)
                        {
                            strPicName += "_plate";
                        }
                        strPicName += "_" + count.ToString() + ".jpg";

                        if (!File.Exists(strPicName))
                        {
                            break;
                        }
                        count++;
                    }
                }
            }
            else
            {                
                if (!Directory.Exists(filePath))
                {
                    Directory.CreateDirectory(filePath);
                }
                strPicName = String.Format(filePath + "{0}_TEMP_{3}_{2}_{1}_{4}.jpg", strNumber, strIP, bIsPlate ? "Plate" : "PlateFull", dt.ToString("yyyyMMdd"), timestamp);
            }
            try
            {
                //find old plate number photo and clear.
                string[] files = Directory.GetFiles(filePath, String.Format("{0}_TEMP_{2}_{1}_*.jpg", strNumber, bIsPlate ? "Plate" : "PlateFull", dt.ToString("yyyyMMdd")));
                foreach (string file in files)
                {
                    try
                    {
                        File.Delete(file);
                        Debug.Print($"车牌识别图片文件已删除: {file}");
                    }
                    catch (IOException e)
                    {
                        Debug.Print($"无法删除车牌识别文件: {file}\n错误: {e.Message}");
                    }
                }
                FileStream fs = new FileStream(strPicName, FileMode.Create, FileAccess.Write);
                BinaryWriter bw = new BinaryWriter(fs);
                bw.Write(picData);
                bw.Close();
                fs.Close();
            }
            catch (System.Exception ex)
            {                
                errorInfo = String.Format("车牌：{0}，IP：{1},保存抓拍：{2}图片，错误：{3}", strNumber, strIP, bIsPlate ? "车牌" : "全景", ex.Message);
                errorEvent?.Invoke(deviceIndex, errorInfo);
            }
        }

        public string ErrorInfo
        {
            get
            {
                return errorInfo;
            }
        }

        public bool IsVideo
        {
            get
            {
                return isVideo;
            }
        }

        public bool IsConnect
        {
            get
            {
                return isConnect;
            }
        }

        public string PicturePath
        {
            get
            {
                return picturePath;
            }
            set
            {
                picturePath = value;
            }
        }

        public string CurrentPlateNumber
        {
            get
            {
                return currentPlateNumber;
            }
        }

        public void CleanPlateNumber()
        {
            currentPlateNumber = "";
            pictureBoxPic.Image = null;
            txtPlateNumber.Text = "";
        }

        [Description("识别设备IP地址"), Category("IP配置")]
        public string Ip
        {
            get
            {
                return ip;
            }
            set
            {
                ip = value;
            }
        }

        [Description("识别设备端口"), Category("IP配置")]
        public int Port
        {
            get
            {
                return port;
            }
            set
            {
                port = value;
            }
        }

        [Description("识别设备用户名"), Category("IP配置")]
        public string UserName
        {
            get
            {
                return userName;
            }
            set
            {
                userName = value;
            }
        }

        [Description("识别设备登录密码"), Category("IP配置")]
        public string Password
        {
            get
            {
                return password;
            }
            set
            {
                password = value;
            }
        }

        [Description("识别索引"), Category("设备组配置")]
        public Int16 DeviceIndex
        {
            get
            {
                return deviceIndex;
            }
            set
            {
                deviceIndex = value;
            }
        }

        private Form myParent = null;
        public Form MyParent { set {
                myParent = value;
            } }
        
        private void Discriminate_Resize(object sender, EventArgs e)
        {
            try
            {
                Console.WriteLine("当前控件高度：" + this.Height.ToString());
                //设置最小宽度
                if (this.Width < 200) this.Width = 200;
                panelBottom.Left = 5;
                panelBottom.Top = this.Height - panelBottom.Height - 5;
                panelBottom.Width = this.Width - 10;
                txtPlateNumber.Width = panelBottom.Width - 5;

                pictureBoxVideo.Left = 5;
                pictureBoxVideo.Top = 5;
                pictureBoxVideo.Width = this.Width - 10;
                pictureBoxVideo.Height = Convert.ToInt32((this.Height - panelBottom.Height) * 0.7);

                pictureBoxPic.Left = 5;
                pictureBoxPic.Width = this.Width - 10;
                pictureBoxPic.Top = pictureBoxVideo.Height + 2;
                pictureBoxPic.Height = this.Height - pictureBoxVideo.Height - panelBottom.Height - 2;

            }
            catch (Exception ex)
            {
                Console.WriteLine("控件：Resize错误：" + ex.Message);
            }
        }

        private void Discriminate_Load(object sender, EventArgs e)
        {
            try
            {
                ipcsdk.ICE_IPCSDK_Init();
                onDeviceEvent = new ipcsdk.ICE_IPCSDK_OnDeviceEvent(SDK_OnDeviceEvent);
                onPlate = new ipcsdk.ICE_IPCSDK_OnPlate(SDK_OnPlate);
                plateNumberInfo = new UpdatePlateInfo(PlateNumberInfo);
                ipcsdk.ICE_IPCSDK_SetDeviceEventCallBack(IntPtr.Zero, onDeviceEvent, new IntPtr(0));
                CheckForIllegalCrossThreadCalls = false;
                Discriminate_Resize(null, null);
            }
            catch (Exception ex)
            {
                errorEvent?.Invoke(deviceIndex, "初始化车牌识别错误：" + ex.Message);
            }
            
        }

        private void btnOpenGate_Click(object sender, EventArgs e)
        {
            openGate();
        }

        public void openGate()
        {   
            try
            {
                btnOpenGate.Enabled = false;
                if (IntPtr.Zero == pUid)
                {
                    errorInfo = "摄像机未连接，开闸失败！";
                    errorEvent?.Invoke(deviceIndex, errorInfo);
                    return;
                }
                uint nRet = ipcsdk.ICE_IPCSDK_OpenGate(pUid);
                if (1 != nRet)
                {
                    errorInfo = "摄像机打开道闸失败！";
                    errorEvent?.Invoke(deviceIndex, errorInfo);
                }
            }
            catch (Exception ex)
            {
                errorInfo = "摄像机打开道闸错误：" + ex.Message;
                errorEvent?.Invoke(deviceIndex, errorInfo);
            }
            finally
            {
                btnOpenGate.Enabled = true;
            }            
        }

        private void btnDiscriminate_Click(object sender, EventArgs e)
        {
            trigger();
        }

        public void trigger()
        {                     
            try
            {
                btnDiscriminate.Enabled = false;
                if (IntPtr.Zero == pUid)
                {
                    errorInfo = "摄像机未连接";
                    errorEvent?.Invoke(deviceIndex, errorInfo);
                    return;
                }
                //StringBuilder strNum = new StringBuilder(32);
                //StringBuilder strColor = new StringBuilder(64);
                //uint len = 0;
                //IntPtr pLen = Marshal.AllocHGlobal(32);
                //byte[] pdata = new byte[1048576];
                uint sucess = ipcsdk.ICE_IPCSDK_TriggerExt(pUid);
                //uint success = ipcsdk.ICE_IPCSDK_Trigger(pUid, strNum, strColor, pdata, 1048576, ref len);//软触发
                //pdata = null;
                //strNum = null;
                //strColor = null;
                if (1 != sucess)
                {
                    errorInfo = "手动识别失败";
                    errorEvent?.Invoke(deviceIndex, errorInfo);
                }
            }
            catch (Exception ex)
            {
                errorInfo = "手动识别错误：" + ex.Message;
                errorEvent?.Invoke(deviceIndex, errorInfo);
            }
            finally
            {
                btnDiscriminate.Enabled = true;
            }            
        }

        public void StartVideo()
        {
            try
            {
                if (IntPtr.Zero == pUid)
                {
                    errorInfo = "车牌识别设备未连接";
                    errorEvent?.Invoke(deviceIndex, errorInfo);
                    isVideo = false;
                    return;
                }
                if (!isVideo)
                {
                    IntPtr videoHwd = IntPtr.Zero;
                    videoHwd = pictureBoxVideo.Handle;
                    if (IntPtr.Zero == videoHwd)
                    {
                        errorInfo = "车牌识别未获得视频播放窗口";
                        errorEvent?.Invoke(deviceIndex, errorInfo);
                        isVideo = false;
                        return;
                    }
                    uint nRet = ipcsdk.ICE_IPCSDK_StartStream(pUid, 1, (UInt32)videoHwd);
                    if (nRet == 0)
                    {
                        errorInfo = "车牌识别预览视频失败";
                        ipcsdk.ICE_IPCSDK_StopStream(pUid);//连接视频失败，调用断开视频接口释放资源
                        errorEvent?.Invoke(deviceIndex, errorInfo);
                        isVideo = false;
                        return;
                    }
                    isVideo = true;
                }
            }
            catch (Exception ex)
            {
                errorEvent?.Invoke(deviceIndex, "车牌识别预览车牌识别错误：" + ex.Message);
            }
        }


        public void StopVideo()
        {            
            try
            {
                if (IntPtr.Zero == pUid)
                {
                    errorInfo = "车牌识别设备未连接";
                    errorEvent?.Invoke(deviceIndex, errorInfo);
                    isVideo = false;
                    return;
                }
                if (isVideo)
                {
                    ipcsdk.ICE_IPCSDK_StopStream(pUid);   
                    isVideo = false;
                } 
            }
            catch (Exception ex)
            {
                errorEvent?.Invoke(deviceIndex, "断开车牌识别预览错误：" + ex.Message);
            }
        }

        public void Connect()
        {
            try
            {
                if (IntPtr.Zero != pUid)
                {
                    errorInfo = "车牌识别摄像机已连接";
                    errorEvent?.Invoke(deviceIndex, errorInfo);
                    return;
                }

                pUid = ipcsdk.ICE_IPCSDK_OpenDevice(ip);
                if (IntPtr.Zero == pUid)
                {
                    errorInfo = "车牌识别摄像机连接失败";
                    isConnect = false;
                    errorEvent?.Invoke(deviceIndex, errorInfo);
                    return;
                }
                isConnect = true;
                ipcsdk.ICE_IPCSDK_SetPlateCallback(pUid, onPlate, new IntPtr(0));
                errorEvent?.Invoke(deviceIndex, "车牌识别设备连接成功！");
            }
            catch (Exception ex)
            {
                errorEvent?.Invoke(deviceIndex, "车牌识别连接错误：" + ex.Message);
            }

        }

        public void Disconnect()
        {
            try
            {
                if (IntPtr.Zero == pUid)
                {
                    errorInfo = "车牌识别设备未连接";
                    errorEvent?.Invoke(deviceIndex, errorInfo);
                    return;
                }
                else
                {
                    if (IsVideo)
                    {
                        ipcsdk.ICE_IPCSDK_StopStream(pUid);
                    }
                }
                mutexThread.WaitOne();
                ipcsdk.ICE_IPCSDK_Close(pUid);
                pUid = IntPtr.Zero;
                mutexThread.ReleaseMutex();
                isVideo = false;
                isConnect = false;
            }
            catch (Exception ex)
            {
                errorEvent?.Invoke(deviceIndex, "车牌识别断开连接错误：" + ex.Message);
            }

        }

        public void Close()
        {
            try
            {                
                if (IntPtr.Zero != pUid)
                {
                    if (IsVideo)
                    {
                        ipcsdk.ICE_IPCSDK_StopStream(pUid);
                    }
                    ipcsdk.ICE_IPCSDK_Close(pUid);
                    pUid = IntPtr.Zero;
                }                
                mutexThread.Close();
                mutexThread = null;
                ipcsdk.ICE_IPCSDK_Fini();
            }
            catch (Exception ex)
            {
                errorInfo = "卸载车牌识别错误：" + ex.Message;
                errorEvent?.Invoke(deviceIndex, errorInfo);
            }

        }

        private void btnInput_Click(object sender, EventArgs e)
        {
            GlobalVariable.manualPlateNumber = "";
            frmCustomerPlateNumber inputForm = new frmCustomerPlateNumber();
            inputForm.xShowDialog(this);
            if (GlobalVariable.manualPlateNumber != "")
            {
                DisCriminateStatus(deviceIndex, GlobalVariable.manualPlateNumber, 99, null, null, 0, 0, 0, 0);
            }
        }

        /*
         * 进行RS485透传
         */
        public void Send(byte[] byteArray)
        {
            try
            {
                uint result = ipcsdk.ICE_IPCSDK_TransSerialPort(pUid, byteArray, (UInt32)byteArray.Length);
                if(result == 0)
                {
                    errorEvent?.Invoke(deviceIndex, "发送命令失败！");
                }
            }
            catch (Exception ex)
            {
                errorEvent?.Invoke(deviceIndex, "发送命令失败:" + ex.Message);
            }
        }

    }
}
